package chat

import (
	"context"
	"errors"
	"time"

	netpack "im/im_server/proto"
	"strconv"

	"google.golang.org/protobuf/proto"
)

type ChatMessageLogic struct {
	chatServer *ChatServer
	redisCmd   *RedisCmd
}

func GenerateChatPlayerIds(ctx context.Context, redisCmd *RedisCmd,
	dbChatRoomMemberList []*netpack.DBChatRoomMember) ([]int64, error) {
	if len(dbChatRoomMemberList) == 0 {
		return nil, errors.New("generate room_member_list empty")
	}

	playerIds := make([]int64, 0, len(dbChatRoomMemberList))
	for _, member := range dbChatRoomMemberList {
		playerIds = append(playerIds, member.PlayerId)
	}
	return playerIds, nil
}

// 生成聊天的消息格式
func GenerateChatMsg(ctx context.Context, redisCmd *RedisCmd, playerId int64, charMsg string,
	channel netpack.RoomChannel) (*netpack.DBChat, error) {
	dbPlayerData, err := redisCmd.HGetRedisPlayerValue(ctx,
		ServerID+HashKeyPlayerIdStr+strconv.FormatInt(playerId, 10), ServerID+HashFiledPlayerStr)
	if err != nil {
		return nil, err
	}

	dbChatData := &netpack.DBChat{}
	chatMsg := &netpack.ChatMsg{
		Channel:     channel,
		ChatMsg:     charMsg,
		PlayerId:    dbPlayerData.PlayerId,
		PlayerName:  dbPlayerData.PlayerName,
		ChatTime:    time.Now().Unix(),
		ChatTimeStr: time.Now().Format("2006-01-02 15:04:05"),
	}

	dbChatData.ChatMsg = chatMsg
	return dbChatData, nil
}

// 聊天室，广播聊天消息
func ChatRoomBroadcastChatMsg(ctx context.Context, redisCmd *RedisCmd, chatServer *ChatServer,
	playerId int64, msg string, roomId int64, channel netpack.RoomChannel,
	dbChatRoomMemberList []*netpack.DBChatRoomMember,
) error {
	playerIds, err := GenerateChatPlayerIds(ctx, redisCmd, dbChatRoomMemberList)
	if err != nil {
		return err
	}

	dbChatData, err := GenerateChatMsg(ctx, redisCmd, playerId, msg, channel)
	if err != nil {
		return err
	}

	scChat := &netpack.SCChat{
		ChatMsg: dbChatData.ChatMsg,
		Error:   netpack.ErrCode_SUCCESS,
	}

	chatServer.msgCallback <- func() {
		for _, playerId := range playerIds {
			playerConn, ok := chatServer.playerConns[playerId]
			if ok {
				playerConn.reply(netpack.MessageID_SC_CHAT, scChat)
			}
		}
	}
	return redisCmd.LPushRedisChatValue(ctx, ServerID+ListKeyRoomChatMsgStr+strconv.FormatInt(roomId, 10), dbChatData)
}

// 大厅聊天流程
func (ch *ChatMessageLogic) HallRoomChannelProcess(csChat *netpack.CSChat, c *Connection) error {
	dbChatData, err := GenerateChatMsg(ctx, ch.redisCmd, c.player.PlayerId, csChat.Msg, csChat.Channel)
	if err != nil {
		return err
	}

	err = ch.redisCmd.LPushRedisChatValue(ctx, ServerID+ListKeyHallChatMsgStr, dbChatData)
	if err != nil {
		return err
	}

	scChat := &netpack.SCChat{
		ChatMsg: dbChatData.ChatMsg,
		Error:   netpack.ErrCode_SUCCESS,
	}

	err = ch.chatServer.BroadcastChat(netpack.MessageID_SC_CHAT, scChat)
	if err != nil {
		return err
	}
	return nil
}

// 处理聊天室流程
func (ch *ChatMessageLogic) ChatRoomChannelProcess(csChat *netpack.CSChat, c *Connection) error {
	dbChatRoomMemberList, err := ch.redisCmd.SMembersRedisRoomMemberListValue(ctx,
		ServerID+SetKeyRoomIdStr+strconv.FormatInt(csChat.RoomId, 10))
	if err != nil {
		return err
	}

	if dbChatRoomMemberList == nil {
		scChat := &netpack.SCChat{
			Error: netpack.ErrCode_CHAT_ROOM_NO_EXIST,
		}
		return c.reply(netpack.MessageID_SC_CHAT, scChat)
	}
	return ChatRoomBroadcastChatMsg(ctx, ch.redisCmd, ch.chatServer,
		c.player.PlayerId, csChat.Msg, csChat.RoomId, csChat.Channel, dbChatRoomMemberList)
}

func (ch *ChatMessageLogic) Chat(msg proto.Message, c *Connection) error {
	csChat, ok := msg.(*netpack.CSChat)
	if !ok {
		return errors.New("parse chat message error")
	}

	if csChat.Channel == netpack.RoomChannel_HALL_ROOM {
		// 大厅聊天消息
		return ch.HallRoomChannelProcess(csChat, c)
	} else if csChat.Channel == netpack.RoomChannel_CHAT_ROOM {
		// 聊天室消息
		return ch.ChatRoomChannelProcess(csChat, c)
	} else {
		scChat := &netpack.SCChat{
			Error:   netpack.ErrCode_CHAT_ROOM_CHANNEL_NOT_FOUND,
			ChatMsg: nil,
		}
		return c.reply(netpack.MessageID_SC_CHAT, scChat)
	}
}
